////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __SPRITE_H__
#define __SPRITE_H__

////////////////////////////////////////////////////////////////////////////////////////////////////

#include "Core/Commons.h"
#include "irrTypes.h"
#include "vector3d.h"
#include "quaternion.h"
#include "ITexture.h"
#include "S3DVertex.h"
#include "SMaterial.h"

////////////////////////////////////////////////////////////////////////////////////////////////////

class CBinaryFile;
//class CRect;
//class CTriangle;

////////////////////////////////////////////////////////////////////////////////////////////////////
// Frames/Anims flags...

#define FLAG_FLIP_X				0x01
#define FLAG_FLIP_Y				0x02
#define FLAG_FLIP_XY			( FLAG_FLIP_X | FLAG_FLIP_Y )

#define FLAG_ROT_0				0x00
#define FLAG_ROT_90				0x04
#define FLAG_ROT_180			0x08
#define FLAG_ROT_270			0x0C

#define FLAG_HYPER_FM			0x10 // Hyper FModule, used by FModules

//#define FLAG_USER0			0x10 // user flag 0
//#define FLAG_NO_FLIPX			0x20 // user flag 1

#define USE_HYPER_FM            FALSE

//////////////////////////////////////////////////
// flags passed as params...

#define FLAG_OFFSET_FM			0x10
#define FLAG_OFFSET_AF			0x20

#define BSPRITE_FLAG_MASK      (FLAG_FLIP_X | FLAG_FLIP_Y | FLAG_OFFSET_FM | FLAG_OFFSET_AF)

////////////////////////////////////////////////////////////////////////////////////////////////////

#define MAX_ALPHA				0xFF

////////////////////////////////////////////////////////////////////////////////////////////////////

#define BST_FLAG_MODULE_TYPE	0x01

#define MODULE_TYPE_IMAGE		252
#define MODULE_TYPE_FILLRECT	254
#define MODULE_TYPE_TRIANGLE	250
#define MODULE_TYPE_FILLTRIANGLE	249

#define FLAG_COLOR_KEY		0x1000
#define FLAG_ALPHA			0x2000
//#define BST_TYPE_RGB16			0x2000
//#define BST_TYPE_RGB32			0x4000
//#define BST_TYPE_IA4			0x8000

#define PIXEL_FORMAT_8888		(short)0x8888
#define PIXEL_FORMAT_0888		(short)0x0888
#define PIXEL_FORMAT_4444		(short)0x4444
#define PIXEL_FORMAT_1555		(short)0x5515
#define PIXEL_FORMAT_0565		(short)0x6505


////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct  
{
	irr::s16 X;
	irr::s16 Y;
	irr::s16 W;
	irr::s16 H;
}SRect;

////////////////////////////////////////////////////////////////////////////////////////////////////

class CSprite
{
private:
	const static irr::u16 BSPRITE_VERSION = 0xA9D1; // bst format used for TN project

public:
	CSprite();
	virtual ~CSprite();

	//////////////////////////////////////////////////

	int		LoadSprite			(CBinaryFile* pFile);
	int		LoadSpriteData		(CBinaryFile* pFile);
	int		LoadSpriteImage		(CBinaryFile* pFile);

	//////////////////////////////////////////////////

	//bool IsImagePixelTransparent(int x, int y);
	//bool IsModulePixelTransparent(int module, int moduleX, int moduleY, int pixelX, int pixelY, int flags);
	//bool IsFModulePixelTransparent(int frame, int fmodule, int fmoduleX, int fmoduleY, int pixelX, int pixelY, int flags);
	//bool IsFramePixelTransparent(int frame, int frameX, int frameY, int pixelX, int pixelY, int flags);
	//bool IsFramePixelTransparentR(int frame, int frameX, int frameY, int pixelX, int pixelY, int flags, int radius);

	inline int	GetNoModules()							{ return m_nModules; }
	inline int	GetNoFModules()							{ return m_nFModules; }
	inline int	GetNoFrames()							{ return m_nFrames; }
	inline int	GetNoAFrames()							{ return m_nAFrames; }
	inline int	GetNoAnims()							{ return m_nAnims; }

	irr::core::rect<irr::f32> GetModuleUVRect(int frame, int fmodule)
	{
		int off      = m_pFrames_FM_Start[ frame ] + fmodule;	
		int nModule    = m_pFModules_Module[ off ];

		irr::core::rect<irr::f32> rect;
		if(m_pTexture!=0)
		{
			const irr::core::dimension2d<irr::u32> texSize = m_pTexture->getSize();
			irr::f32 maxX = texSize.Width-1;
			irr::f32 maxY = texSize.Height-1;
			rect.UpperLeftCorner.X = (irr::f32)(m_pModules_X[nModule])/maxX;
			rect.UpperLeftCorner.Y = (irr::f32)(m_pModules_Y[nModule])/maxY;
			rect.LowerRightCorner.X = (irr::f32)(m_pModules_X[nModule]+m_pModules_Width[nModule])/maxX;
			rect.LowerRightCorner.Y = (irr::f32)(m_pModules_Y[nModule]+m_pModules_Height[nModule])/maxY;
		}

		return rect;
	}

	virtual inline int	GetModuleWidth( int nModule ) const		{ return m_pModules_Width[ nModule ]; }
	virtual inline int	GetModuleHeight( int nModule ) const	{ return m_pModules_Height[ nModule ]; }

	virtual inline int	GetFModuleOffsetX( int nFModule )		{ return m_pFModules_OffsetX[ nFModule ]; }
	virtual inline int	GetFModuleOffsetY( int nFModule )		{ return m_pFModules_OffsetY[ nFModule ]; }
	virtual inline int	GetFModuleFlags( int nFModule )			{ return m_pFModules_Flags[ nFModule ]; }

	
	virtual inline int	GetAFrameFlags( int anim , int aframe )		{ return m_pAFrames_Flags[ m_pAnims_AF_Start[ anim ] + aframe ]; }
	virtual inline int	GetAFrameOffsetX( int anim , int aframe )	{ return m_pAFrames_OffsetX[ m_pAnims_AF_Start[ anim ] + aframe ]; }
	virtual inline int	GetAFrameOffsetY( int anim , int aframe )	{ return m_pAFrames_OffsetY[ m_pAnims_AF_Start[ anim ] + aframe ]; }

	inline int	GetFrameFModuleStart( int frame )			{ return m_pFrames_FM_Start[ frame ]; }	
	inline int	GetAFrameTime( int anim, int aframe )			{ return m_pAFrames_Time[ m_pAnims_AF_Start[ anim ] + aframe ]; }
	inline void	SetAFrameTime( int anim, int aframe, int time )	{ m_pAFrames_Time[ m_pAnims_AF_Start[ anim ] + aframe ]	=	time; }
	inline int	GetAFrames( int anim )							{ return m_pAnims_NoAFrames[ anim ]; }
	inline int	GetFModules( int frame )						{ return m_pFrames_NoFModules[ frame ]; }
	inline int	GetFModuleModule( int fmodule )					{ return m_pFModules_Module[ fmodule ]; }
	inline int	GetAFrame(int anim, int aframe)					{ return m_pAFrames_Frame[ m_pAnims_AF_Start[ anim ] + aframe ]; }

	//////////////////////////////////////////////////
	//void GetFrameRects ( CRect* rc, int frame , int flag , int type  );
	//void GetFrameTriangle ( CTriangle* tri, int frame , int flag , int type  );
	void GetAFrameRect ( irr::core::rect<short>& rc, int anim, int aframe, int posX, int posY, irr::u32 flags, int hx, int hy ) const;
	void GetFrameRect  ( irr::core::rect<short>& rc, int frame, int posX, int posY, irr::u32 flags, int hx, int hy ) const;
	//void GetModuleRect ( CRect* rc, int module, int posX, int posY, irr::u32 flags ) const;
    void GetFModuleRect( irr::core::rect<short>& rc, int frame, int fmodule, int posX, int posY, int flags ) const;

	int GetFrameWidth(int frame);
	int GetFrameHeight(int frame);

	int  GetAnimDuration( int anim );

	//////////////////////////////////////////////////

	inline bool IsModuleImage(int nID)		{ return (!(m_nFlags & BST_FLAG_MODULE_TYPE)) || (m_pModules_Type[nID] == MODULE_TYPE_IMAGE); }
	inline bool IsModuleFillRect(int nID)	{ return (m_nFlags & BST_FLAG_MODULE_TYPE) && (m_pModules_Type[nID] == MODULE_TYPE_FILLRECT); }
	inline bool IsModuleTriangle(int nID)	{ return (m_nFlags & BST_FLAG_MODULE_TYPE) && (m_pModules_Type[nID] == MODULE_TYPE_TRIANGLE || m_pModules_Type[nID] == MODULE_TYPE_FILLTRIANGLE); }

	//////////////////////////////////////////////////

	void PaintAFrame	( int anim, int aframe, int posX, int posY, irr::u32 flags = 0, irr::u8 alpha = MAX_ALPHA );
	void PaintFrame		( int frame, int posX, int posY, irr::u32 flags = 0, irr::u8 alpha = MAX_ALPHA, bool isUseAlphaChannelOfTexture = true );
	void PaintFModule	( int frame, int fmodule, int posX, int posY, irr::u32 flags, irr::u8 alpha = MAX_ALPHA, bool isUseAlphaChannelOfTexture = true);
	void PaintModule	( int module, int posX, int posY, irr::u32 flags, irr::u8 alpha = MAX_ALPHA, bool isUseAlphaChannelOfTexture = true);

	void PaintAFrame	( int anim, int aframe, const irr::core::vector3df& pos, irr::u32 flags = 0, irr::u8 alpha = MAX_ALPHA );
	void PaintFrame		( int frame, const irr::core::vector3df& pos, irr::u32 flags = 0, int offX = 0, int offY = 0, irr::u8 alpha = MAX_ALPHA );
	void PaintFModule	( int frame, int fmodule, const irr::core::vector3df& pos, irr::u32 flags, int offX = 0, int offY = 0, irr::u8 alpha = MAX_ALPHA);
	void PaintModule	( int module, const irr::core::vector3df& pos, irr::u32 flags, int offX = 0, int offY = 0, irr::u8 alpha = MAX_ALPHA);

	//////////////////////////////////////////////////

	static void FillRect(int x, int y, int w, int h, int argb);
	static void FillRect(const irr::core::rect<int>& rt, int argb);

	//////////////////////////////////////////////////

	//irr::video::E_TEXTURE_FILTER_TYPE	GetFilterType() { return m_filterType; }
	//void	SetFilterType(irr::video::E_TEXTURE_FILTER_TYPE filterType){ m_filterType = filterType; }

	void	SetPalette( int nPal ); 
	int		GetPalette();
	
	inline	void	SetColor(irr::u32 color)	{m_nColor = color;}
	inline	irr::u32		GetColor() {return m_nColor;}

	inline	void	SetScale(irr::f32 scale)	{ m_fScale = scale;}
	inline	irr::f32		GetScale()			{ return m_fScale;}
	inline	bool	IsScaled()			{ return m_fScale != 1.0f;}
	
	void					SetAngle(const irr::core::quaternion& angle);
	void					SetAngle(const irr::f32 angle)	{ m_fAngle = angle; }
	
	float					GetAngle() {return m_fAngle;}

//	inline const irr::core::quaternion&	GetAngle()										{return m_fAngle;}	
	//irr::u8*		GetTexture(int nTexture);
	//irr::u32		GetTextureSize(int nTexture);
	//irr::u32		GetTextureWidth(int nTexture);
	//irr::u32		GetTextureHeight(int nTexture);
	//irr::u32		GetTextureID(int nTexture , int nPal);
	//////////////////////////////////////////////////

	//void	MultiplyAnimTime(int factor);

	//////////////////////////////////////////////////

	//void	SetLinearFilter();
	//void	SetNearFilter();

	static void SetClip(int x, int y, int w, int h);
	static void ResetClip();

	irr::video::ITexture* GetTexture() { return	m_pTexture; }

protected:
	//////////////////////////////////////////////////
	//Data members

	// Memory Buffers...
	irr::u8*			m_pInternalBuffer;
	irr::u8*			m_pInternalBufferPointer;

protected:

	// Flags ...
	irr::u16			m_nFlags;

	// Modules...
	irr::u16			m_nModules;
	irr::u8*			m_pModules_Type;
	irr::s16*		m_pModules_X;
	irr::s16*		m_pModules_Y;
	irr::u16*		m_pModules_Width;
	irr::u16*		m_pModules_Height;

	// FModules...
	irr::u16			m_nFModules;
	irr::u16*		m_pFModules_Module;
	irr::u8*			m_pFModules_Flags;
	irr::s16*		m_pFModules_OffsetX;
	irr::s16*		m_pFModules_OffsetY;

	// Frames...
	irr::u16			m_nFrames;
	irr::u8*			m_pFrames_NoFModules;
	irr::u16*		m_pFrames_FM_Start;
	SRect*		m_pFrames_RC;

	// AFrames...
	irr::u16			m_nAFrames;
	irr::u16*		m_pAFrames_Frame;
	irr::u8*			m_pAFrames_Time;
	irr::u8*			m_pAFrames_Flags;
	irr::s16*		m_pAFrames_OffsetX;
	irr::s16*		m_pAFrames_OffsetY;

	// Anims...
	irr::u16			m_nAnims;
	irr::u8*			m_pAnims_NoAFrames;
	irr::u16*		m_pAnims_AF_Start;

	////////////////////////////////////////////////////
	//// Texture...

	irr::video::ITexture*	m_pTexture;

	//////////////////////////////////////////////////

	//3d stuff
	irr::u16 m_aIndices[6];
	irr::video::S3DVertex m_aVertices[4];
	irr::f32 m_fModuleDepth;
public:
	irr::video::SMaterial* m_pMaterial;

protected:
	//////////////////////////////////////////////////
	int			m_nCrtPalette;

	//////////////////////////////////////////////////
	irr::u32			m_nColor;
	irr::f32			m_fScale;

	irr::f32			m_fAngle;
	int					m_rotateX, m_rotateY;
	//////////////////////////////////////////////////

	static irr::core::rect<irr::s32>*		s_clipRect;
	//static bool						s_useClip;
//private:
//	irr::video::E_TEXTURE_FILTER_TYPE m_filterType;
private:
	float GetEnlargeRate( irr::c8 *pBaseStr, irr::c8 *pOutStr);
private:
	float m_imageEnlargeRate;
};

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //__SPRITE_H__

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
